<?php
namespace addons\sign\libs;
// 签到类
class SignIn{
	// 共签到7天，7天后重置
	public $day = 7;
	// 会员ID
	public $member_id = '';
	// Redis对象
	public $redis = '';
	// 当前第几天，从0开始
	public $currentDay = '';
	// 今天签到成功
	public $signSuccess = false;
	// 时间
	public $lastDate = '';
	public $ttl = 0;
	/**
	 * 签到初始化
	 * @param int $member_id
	 * @param int $day
	 */
	public function __construct($member_id = 0 , $day = 0) {
		$member_id && $this->member_id = $member_id;
		$day && $this->day = $day;
		$this->redis = getRedis();
//		$this->ttl = [
//			$this->redis->ttl($this->getUserLastTimeKey()) ,
//			$this->redis->ttl($this->getUserKey())
//		];
	}

	/**
	 * 用户签到key
	 * @return string
	 * @author Colin <xiongxinsheng@yikaosheng.com>
	 * @date 2021-03-03 上午11:48
	 */
	public function getUserKey(){
		return 'shopUserSignIn:state:' . $this->member_id;
	}

	/**
	 * 用户一个周期内最后一次签到的日期
	 * @return string
	 * @author Colin <xiongxinsheng@yikaosheng.com>
	 * @date 2021-03-03 上午11:48
	 */
	protected function getUserLastTimeKey(){
		return 'shopUserSignIn:lastDate:' . $this->member_id;
	}

	/**
	 * 签到方法
	 * @author Colin <xiongxinsheng@yikaosheng.com>
	 * @date 2021-03-03 上午11:52
	 */
	public function todaySign(){
		/**
		 * 1.获取用户是否有签到的key
		 * 2.生成用户7天的key
		 * 3.校验是否有连续的打卡记录
		 * 4.如果不连续则重新累计
		 */
		$day = $this->getDayNumber();
		$userKey = $this->getUserKey();
		if ($day == 0){
			// 要么是断签了，要么是重新开始了
			// 检查今天是否签到
			$sign = $this->redisBitField($userKey , $day);
			if (!$sign){
				// 如果是第一天，则重置签到数据
				$this->redis->del($userKey);
				// 今天没有签到，则签到
				$this->signToday($userKey , $day);
			}else{
				// 如果已经签到了，则把其它天数给重置
				if ($this->redis->bitCount($userKey) != 1){
					for ($i = 1 ; $i <= 6 ; $i ++){
						$this->redis->setBit($userKey , $i , 0);
					}
				}
			}
			$this->currentDay = $day;
		}else {
			// 不是第一天了，则校验是否有连续签到
			$preDay = $day - 1;
			$preSign = $this->redisBitField($userKey , $preDay);
			if (!$preSign){
				// 上一天没有签到，则断签了，需要重新来
				$this->redis->del($userKey);
				$this->redis->del($this->getUserLastTimeKey());
				// 开启签到流程
				$this->todaySign();
			}else{
				// 上一天签到了，则今天正常签到
				$this->signToday($userKey , $day);
				$this->currentDay = $day;
			}
		}
	}

	/**
	 * 获取今天是第几天打卡
	 * @return int
	 * @author Colin <xiongxinsheng@yikaosheng.com>
	 * @date 2021-03-03 下午2:33
	 */
	public function getDayNumber(){
		$start_date = date('Ymd');
		$lastDate = $this->redis->get($this->getUserLastTimeKey());
		// 如果获取的最小日期小雨今天则重新创建
		if (!$lastDate || $lastDate < $start_date){
			// 没有则创建
			$lastDate = strtotime('+' . ($this->day - 1) . ' day 23:59:59' , time());
			$expire = $lastDate - time();
			$lastDate = date('Ymd' , $lastDate);
			$this->redis->set($this->getUserLastTimeKey() , $lastDate);
			$this->redis->expire($this->getUserLastTimeKey() , $expire);
		}
		$day = $this->getManyDay($lastDate , $start_date , $this->day);
		$this->currentDay = $day;
		$this->lastDate = $lastDate;
		return $day;
	}

	/**
	 * 获取今天是第几天
	 * @param $lastDate
	 * @param $start_date
	 * @param $day
	 * @return int
	 * @author Colin <xiongxinsheng@yikaosheng.com>
	 * @date 2021-04-08 上午9:57
	 */
	public function getManyDay($lastDate , $start_date , $day){
		$offset = floor((strtotime($lastDate) - strtotime($start_date)) / 86400);
		$day = intval($day - $offset);
		return $day - 1; // 下标从0开始
	}

	/**
	 * 返回签到天数
	 * @return array 天数从0开始，取天数需+1
	 * @author Colin <xiongxinsheng@yikaosheng.com>
	 * @date 2021-03-03 下午2:06
	 */
	public function signDays(){
		$days = [];
		for ($i = 0 ; $i < $this->day ; $i ++){
			$selected = false;
			if ($this->redisBitField($this->getUserKey() , $i)){
				$selected = true;
			}
			array_push($days , ['day' => $i , 'selected' => $selected]);
		}
		return $days;
	}

	/**
	 * 获取当前第几天
	 * @return string
	 * @author Colin <xiongxinsheng@yikaosheng.com>
	 * @date 2021-03-03 下午2:20
	 */
	public function getCurrentDay(){
		return $this->currentDay;
	}

	/**
	 * 获取是否签到
	 * @param $userKey
	 * @param $offset
	 * @return mixed
	 * @author Colin <xiongxinsheng@yikaosheng.com>
	 * @date 2021-03-03 上午11:40
	 */
	public function redisBitField($userKey = '' , $offset = ''){
		$res = $this->redis->rawCommand('bitfield' , $userKey , 'get' , 'u1' , $offset);
		return $res[0];
	}

	/**
	 * 打卡今天
	 * @param $userKey
	 * @param $i
	 * @return bool
	 * @author Colin <xiongxinsheng@yikaosheng.com>
	 * @date 2021-03-03 上午11:39
	 */
	protected function signToday($userKey , $i){
		$res = $this->redisBitField($userKey , $i);
		if($res == 1){
			return true;
		}
		$this->redis->setBit($userKey , $i , 1);
		// 设置过期时间
		$this->redis->expire($userKey , $this->redis->ttl($this->getUserLastTimeKey()));
		$this->signSuccess = true;
		return true;
	}

	/**
	 * 打卡取消
	 * @param $userKey
	 * @param $i
	 * @return bool
	 * @author Colin <xiongxinsheng@yikaosheng.com>
	 * @date 2021-03-04 下午2:39
	 */
	public function signTodayCancel($userKey , $i){
		if($this->redisBitField($userKey , $i) == 0){
			return true;
		}
		$this->redis->setBit($userKey , $i , 0);
		return true;
	}

	/**
	 * 重置用户签到
	 * @author Colin <xiongxinsheng@yikaosheng.com>
	 * @date 2021-03-18 上午10:57
	 */
	public function resetUserSign(){
		if (!$this->member_id){
			return false;
		}
		$this->redis->del($this->getUserLastTimeKey());
		$this->redis->del($this->getUserKey());
		return true;
	}
}